package cn.com.nes.common.util;

import cn.com.nes.common.em.TimeType;
import cn.hutool.core.util.ObjectUtil;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TimeUtils {
    private static final ZoneId SYSTEM_ZONE_ID = ZoneId.systemDefault();
    private static final String P_DAY = "yyyy-MM-dd";
    private static final String P_SECOND = P_DAY + " HH:mm:ss";
    private static final Integer TIME_TYPE_1 = 1;
    private static final Integer TIME_TYPE_2 = 2;
    private static final Integer TIME_TYPE_3 = 3;
    /**
     * 处理时间跨度
     * @param startTime 起始时间
     * @param endTime 截止时间
     * @param duration 默认时间间隔(毫秒数)
     * @return 起止时间map
     */
    public static Map<String, Date> handleTimeSpan(Date startTime, Date endTime, Long duration) {
        Map<String, Date> timeMap = new HashMap<>(2);
        timeMap.put("startTime", startTime);
        timeMap.put("endTime",endTime);
        //处理起止日期
        long year = 365*24*60*60*1000L;
        if (ObjectUtil.isNull(duration)) {
            duration = year;
        }
        //起始日期为空,截止日期不为空,设置起始日期为当前时间前一年
        if (ObjectUtil.isNull(startTime) && ObjectUtil.isNotNull(endTime)) {
            timeMap.put("startTime", new Date(System.currentTimeMillis()- year));
        }
        //截止日期为空,起始日期不为空,设置截止日期为起始日期后一年或当前时间
        if (ObjectUtil.isNotNull(startTime) && ObjectUtil.isNull(endTime)) {
            Long current = System.currentTimeMillis();
            Long span = current - startTime.getTime();
            //
            if (span > year) {
                timeMap.put("end", new Date(startTime.getTime() + year));
            } else {
                timeMap.put("endTime", new Date(current));
            }
        }
        //起止日期都为空
        if (ObjectUtil.isNull(startTime) && ObjectUtil.isNull(endTime)) {
            Long current = System.currentTimeMillis();
            timeMap.put("endTime", new Date(current));
            timeMap.put("startTime", new Date(current - duration));
        }
        //起止时间都不为空
        if (ObjectUtil.isNotNull(startTime) && ObjectUtil.isNotNull(endTime)) {
            //计算时间跨度
            Long span = endTime.getTime() - startTime.getTime();
            //起止时间跨度超过一年,设置起始时间为截止时间前一年
            if (span > year) {
                timeMap.put("startTime", new Date(endTime.getTime() - year));
            }
        }
        return timeMap;
    }
    public static DateFormat dateFormat(String pattern) {
        return new SimpleDateFormat(pattern);
    }

    /**
     * 日期格式化：MM月dd日 hh:mm
     *
     * @param date
     * @return
     */
    public static String date2Str(Date date) {
        if (date == null) {
            return "";
        }
        return dateFormat(P_DAY).format(date);
    }

    /**
     * 日期格式化：MM月dd日 hh:mm 2018-02-05 11:22:55
     * @param String
     * @return date
     */
    public static Date str2Date(String datestr) {
        try {
            return dateFormat(P_SECOND).parse(datestr);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取默认格式的当前时间 yyyy-MM-dd HH:mm:ss
     */
    public static String getTime(){
        return getTime(TimeType.yyyy_MM_dd_HH_mm_ss);
    }

    /**
     * 获取默认格式的当前时间戳 yyyy-MM-dd HH:mm:ss.SSS
     */
    public static String getTimesTamp(){
        return getTime(TimeType.yyyy_MM_dd_HH_mm_ss_SSS);
    }

    /**
     *	根据对应枚举类型的格式获取时间
     */
    public static String getTime(TimeType timeType){
        if(timeType.type() == TIME_TYPE_1) {
            return LocalDateTime.now().format(patternFormat(timeType));
        }
        else if(timeType.type() == TIME_TYPE_2) {
            return LocalDate.now().format(patternFormat(timeType));
        }
        else {
            return LocalTime.now().format(patternFormat(timeType));
        }

    }

    /**
     *	根据设定的时间减去设定的天数得到具体的时间
     */
    public static Date subtractDay(Date d, int day) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) - day);
        return cal.getTime();
    }

    /**
     *	根据设定的时间减去设定的小时得到具体的时间
     */
    public static Date subtractHour(Date d, int hour) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.set(Calendar.HOUR, cal.get(Calendar.HOUR) - hour);
        return cal.getTime();
    }

    /**
     * 给指定日期添加天数，并返回
     *@author lcf
     *@date 2018年6月22日
     *@version 1.0
     */
    public static Date addDay(Date d, int day) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + day);
        return cal.getTime();
    }


    /**
     * @param date
     *            日期
     * @param otherDate
     *            另一个日期
     * @return 相差天数
     */
    public static long getIntervalDays(Date date, Date otherDate) {
        long time = otherDate.getTime() - date.getTime();
        return time / (24 * 60 * 60 * 1000);
    }

    /**
     * 把字符串类型的时间格式化为Date类型
     * @param String 日期格式参数
     * @param TimeType 枚举
     * @return date 日期
     */
    public static Date getDateByString(String time, TimeType timeType){
        if(timeType.type() == TIME_TYPE_1) {
            return Date.from(LocalDateTime.parse(time, patternFormat(timeType)).atZone(SYSTEM_ZONE_ID).toInstant());
        }
        else if(timeType.type() == TIME_TYPE_2) {
            return Date.from(LocalDate.parse(time, patternFormat(timeType)).atStartOfDay().atZone(SYSTEM_ZONE_ID).toInstant());
        }
        else {
            return Date.from(LocalTime.parse(time, patternFormat(timeType)).atDate(LocalDate.now()).atZone(SYSTEM_ZONE_ID).toInstant());
        }
    }

    /**
     * 把Date类型的时间格式化为String类型
     */
    public static String getStringByDate(Date time, TimeType timeType){
        LocalDateTime localDateTime = LocalDateTime.ofInstant(time.toInstant(), SYSTEM_ZONE_ID);
        if(timeType.type() == TIME_TYPE_1) {
            return localDateTime.format(patternFormat(timeType));
        }
        else if(timeType.type() == TIME_TYPE_2) {
            return localDateTime.toLocalDate().format(patternFormat(timeType));
        }
        else {
            return localDateTime.toLocalTime().format(patternFormat(timeType));
        }
    }

    /**
     * 比较两个时间的大小
     * <pre>
     * 	start <  end   ==> true
     * 	end   >  start ==> false
     * </pre>
     * @param start	开始时间
     * @param end	结束时间
     */
    public static boolean compare(String start, String end, TimeType type){
        return compare(getDateByString(start, type), getDateByString(end, type));
    }

    /**
     * 比较两个时间的大小
     * <pre>
     * 	start <  end   ==> true
     * 	end   >  start ==> false
     * </pre>
     * @param start	开始时间
     * @param end	结束时间
     */
    public static boolean compare(Date start, Date end){
        return end.getTime() >= start.getTime();
    }


    /**
     * 比较某个时间是否在时间段内
     * @param start	开始时间
     * @param end	结束时间
     * @param param	判断的时间
     */
    public static boolean compare(Date param,Date start, Date end){
        if (end.getTime() > param.getTime() && param.getTime() > start.getTime()){
            return true;
        } else if (end.getTime() >= param.getTime() && param.getTime() > start.getTime()) {
            return true;
        } /*
		每单的结束时间和其他单的开始时间重叠
		else if (end.getTime() > param.getTime() && param.getTime() >= start.getTime()) {
			return true;
		}*/ else if (start.getTime() == end.getTime() && param.getTime() == start.getTime()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 与系统当前时间进行比较
     * <pre>
     * 	time  <  now  ==> true
     * 	now   >  time ==> false
     * </pre>
     * @return
     */
    public static boolean compare(Date time){
        return System.currentTimeMillis() >= time.getTime();
    }

    /**
     * 与系统当前时间进行比较
     * <pre>
     * 	time  <  now  ==> true
     * 	now   >  time ==> false
     * </pre>
     * @param time
     * @return
     */
    public static boolean compare(String time, TimeType type){
        return System.currentTimeMillis() >= getDateByString(time, type).getTime();
    }

    /**
     * 验证传入的日期是否符合指定格式 并验证是否合法
     * @param time
     * @param type
     * @return
     */
    public static boolean validate(String time, TimeType type){
        try {
            //TODO 试试能不能用JDK8模式改进一下~
            SimpleDateFormat dateFormat = new SimpleDateFormat(type.value());
            dateFormat.setLenient(false);
            dateFormat.parse(time);
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 转化时间类型
     * @param type
     * @return
     */
    private static DateTimeFormatter patternFormat(TimeType type){
        return DateTimeFormatter.ofPattern(type.value());
    }

    /**
     *  获得年份
     * @param d
     * @return
     */
    public static int getYear(Date d){
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        return cal.get(Calendar.YEAR);
    }

    /**
     * 校验日期格式 yyyy.MM.dd
     * @param date
     * @return true:格式异常 false:格式正常
     */
    public static boolean checkDate(String date) {
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
            // 用来控制是否将正确格式的不正确时间转化成正确的时间，默认为true，设置为false时，如果时间不正确，不会自动转化，，而是抛出java.text.ParseException异常。
            dateFormat.setLenient(false);
            dateFormat.parse(date);
        } catch (ParseException e) {
            return true;
        }
        return false;
    }

    /**
     * 计算两个时间的时间差
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static String dateDiff(Date startTime, Date endTime) {
        // 一天的毫秒数
        long nd = 1000 * 24 * 60 * 60;
        // 一小时的毫秒数
        long nh = 1000 * 60 * 60;
        // 一分钟的毫秒数
        long nm = 1000 * 60;
        // 一秒的毫秒数
        long ns = 1000;

        long diff = endTime.getTime() - startTime.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        long sec = diff % nd % nh % nm / ns;
        String daystr = day < 10 ? "0" + day : "" + day;
        String hourstr = hour < 10 ? "0" + hour : "" + hour;
        String minstr = min < 10 ? "0" + min : "" + min;
        String secstr = sec < 10 ? "0" + sec : "" + sec;
        return daystr + "天" + hourstr + "小时";
        //return daystr + "天" + hourstr + "小时" + minstr + "分钟" + secstr + "秒";
    }

    /**
     * 计算两个时间的时间差
     *
     * @param Date endTime2 结束时间
     * @param Date startTime2 传入时间
     * @return String 相差的天数
     */
    public static String getDatePoor(Date endDate, Date nowDate) {

        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;

        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 获取后一天日期
     * @param time
     * @return
     */
    public static String nextDate(String time) {
        String[] split = time.split("-");
        int year = Integer.valueOf(split[0]);
        int month = Integer.valueOf(split[1]);
        int day = Integer.valueOf(split[2]);
        if(year%4==0&&year%100!=0&&month==2&&day==29){//当为润年的时候,二月有29天
            month=month+1;
            day=1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";
        }
        else if(month==2&&day==28){//当该年为平年的时候，二月为28天,输出日期后一天，月份加1，将具体几号置为1
            month=month+1;
            day=1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";

        }
        else if(month==12&&day==31) {//当输入月份为12月31日此情况下要输出后一天则要将其年份加1，月份和日期号置为1
            year=year+1;
            month=1;
            day=1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";
        }
        //当输入月大，日子为最大31号，则执行月份+1，日期号置为1
        else if(month==1&&day==31||month==3&&day==31||month==5&&day==31||month==7&&day==31||month==8&&day==31||month==10&&day==31 ){
            month=month+1;
            day=1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";

        }
        else if(month==4&&day==30||month==6&&day==30||month==9&&day==30||month==11&&day==30){
            month=month+1;
            day=1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";
        }
        else {
            day=day+1;
            return year+"年"+(month>=10?month:"0"+month)+"月"+(day>=10?day:"0"+day)+"日";
        }
    }

}
